package com.example.springboottest.example.io.redirect.appserver.nio2;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

/**
 * nio2对nio的功能改进，最重要是对异步I/O即AIO的支持
 * 1、通道      和nio类似，但改为AsynchronousSocketChannel，继承Channel
 * 2、缓冲区    和nio类似
 * 3、AIO的有两种实现方式  Future和CompletionHandler
 * Future 需要程序自己监测I/O状态或者通过Feture.get()等待I/O操作结束
 * CompletionHandler 则由JDK监测I/O状态，程序只需要实现每种状态的处理即可
 * <p>
 * <p>
 * 本例子主要针对Future实现
 */
public class NIO2Client {
    private AsynchronousSocketChannel channel;
    private CharBuffer charBuffer;
    private CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
    private BufferedReader clientInput = new BufferedReader(new InputStreamReader(System.in));

    public void init() throws Exception {
        //创建channel
        channel = AsynchronousSocketChannel.open();
        if (channel.isOpen()) {
            channel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024);
            channel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024);
            channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);

            Void connect = channel.connect(new InetSocketAddress("127.0.0.1", 8080)).get();
            if (connect != null)
                throw new RuntimeException("链接服务器失败");
        } else
            throw new RuntimeException("异步通道未打开");
    }

    public void start() throws Exception {
        System.out.println("输入客户端请求：");
        String request = clientInput.readLine();
        //发送客户端请求
        channel.write(ByteBuffer.wrap(request.getBytes())).get();
        //创建读取缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        //读取服务端响应
        while (channel.read(buffer).get() != -1) {
            buffer.flip();
            charBuffer = decoder.decode(buffer);
            String response = charBuffer.toString().trim();
            System.out.println("服务端响应" + response);
            if (buffer.hasRemaining())
                buffer.compact();
            else
                buffer.clear();
            //读取并发送下一次请求
            request = clientInput.readLine();
            channel.write(ByteBuffer.wrap(request.getBytes())).get();
        }
    }

    public static void main(String[] args) throws Exception {
        NIO2Client client = new NIO2Client();
        client.init();
        client.start();
    }
}
